/* User responsible for freeing cstring. new_cstring, cstring_substr, will 
 * return newly allocated cstring structures that must be free by user.
 */

#include <assert.h>
#include "safe_malloc.h"
#include "cstring.h"

#define MIN(a,b) (a < b) ? a : b

cstring_t* new_cstring()
{
  cstring_t* tmp = (cstring_t*)safe_malloc(sizeof(cstring_t));
  tmp->string = 0;
  tmp->length = 0;
  
  return tmp;
}

int cstring_cmp(cstring_t* left, cstring_t* right)
{
  return strcmp(left->string, right->string);
}

int cstring_casecmp(cstring_t* left, cstring_t* right)
{
  return strcasecmp(left->string, right->string);
}

int cstring_cmp_oldstr(cstring_t* left, const char* right)
{
  return strcmp(left->string, right);
}

void cstring_cat(cstring_t* left, cstring_t* right)
{
  cstring_cat_oldstr(left, right->string);
}
/*TODO: cstring_casecmp_oldstr*/
/*TODO: */

void cstring_cat_oldstr(cstring_t* left, const char* right)
{
  int oldlen = strlen(right);
  char* newstr = (char*)safe_malloc(left->length + oldlen + 1);
  memset(newstr, 0, left->length + oldlen + 1);
  strncat(newstr, left->string, left->length);
  strncat(newstr, right, oldlen);

  if(left->string) {
    free(left->string);
  }

  left->string = newstr;
  left->length = strlen(left->string);
}

/*start index is inclusive and end index is exclusive*/
cstring_t* cstring_substr(cstring_t* str, int start, int end)
{
  assert(start >= 0 && end <= str->length);
  assert(start < end);
  int sublen = end - start;
  char* substr = (char*)safe_malloc(sublen+1);
  int i,j;
  for(i=0,j=start; j<end; i++,j++) {
    substr[i] = str->string[j];
  }
  substr[i] = '\0';
  cstring_t* newstr = new_cstring();
  cstring_cat_oldstr(newstr, substr);

  return newstr;
}

cstring_t* cstring_dup(cstring_t* str)
{
  cstring_t* dup = new_cstring();
  dup->string = strdup(str->string);
  dup->length = str->length;
  return dup;
}

int cstring_len(cstring_t* str)
{
  return str->length;
}

/* Splits will return a clist_t of cstring_t or char*  so the 'void* data' in 
 * cnode_t * will point to a cstring_t or char*.
 */


clist_t* cstring_split(cstring_t* str, cstring_t* delim)
{
  return NULL;
}

/*returns clist_t of 'cstring_t*' */
/*returns NULL the string was only comprised of delimeters*/
/*return a one element clist if nothing could be split*/
clist_t* cstring_split_oldstr(cstring_t* str, const char* delim)
{
  cstring_t* tmp = cstring_dup(str);
  char* s = tmp->string;

  char* reentrant;
  char* token = strtok_r(s, delim, &reentrant);
  if(token == NULL) return NULL;
  if(strncmp(str->string, token, strlen(str->string)) == 0) {
    clist_t* list = new_clist();
    clist_push_back(list, (void*)tmp);
    return list;
  }

  clist_t* list = new_clist();
  while(token) {
    cstring_t* cp = new_cstring();
    cstring_cat_oldstr(cp, token);
    clist_push_back(list, (void*)cp);
    token = strtok_r(NULL, delim, &reentrant);
  }
  cstring_free(tmp);
  return list;
}

clist_t* cstring_split_char(cstring_t* str, char delim)
{
  return NULL;
}

void cstring_free(cstring_t* str)
{
  if(str) {
    if(str->string) {
      free(str->string);
    }
    free(str);
  }
}
